package squelette;

import java.util.ArrayList;

import Lib3d.Vector3d;

public class Mass {

	public static final float weight = 10.0f;	// en Grammes.

	public boolean isAttached = false;	// Indique si la masse est attachée, et donc POSSEDE TOUJOURS une vitesse/acceleration nulle. Calculs forcés.
	public boolean isAttached() { return isAttached; }
	public void setAttached(boolean isAttached) { this.isAttached = isAttached;	}

	private Vector3d position;
	public Vector3d getPosition() { return position; }
	public void setPosition(Vector3d position) { this.position = position; }
	
	private Vector3d speed = new Vector3d(0, 0, 0);
	public Vector3d getSpeed() { return speed; }
	public void setSpeed(Vector3d speed) {				// Si IsAttached, ne modifie pas la vitesse.
		if (!isAttached) {
			this.speed = speed;
		}
	}
	
	private Vector3d newSpeed = new Vector3d(0, 0, 0);
	public Vector3d getNewSpeed() { return newSpeed; }
	public void setNewSpeed(Vector3d newSpeed) {		// Si IsAttached, ne modifie pas la vitesse.
		if (!isAttached) {
			this.newSpeed = newSpeed;
		}
	}
	
	private Vector3d force;								// Force que subit la masse.
	public Vector3d getForce() { return force; }
	
	private ArrayList<Mass> neighbourMasses = new ArrayList<Mass>();		// Contient les masses voisines auquelle la masse courante est liée.
	public ArrayList<Mass> getNeighbourMasses() { return neighbourMasses; }
	
	private ArrayList<Float> initialLengthSprings = new ArrayList<Float>();	// Contient la longueur initial du ressort selon la masse voisine.
	
	public Mass(Vector3d position, boolean isAttached) {
		this.position = position;
		this.isAttached = isAttached;
	}

	/**
	 * Ajoute une masse dans la liste des masses voisines.
	 * @param m Masse à ajouter.
	 */
	public void addNeighbourMasses(Mass m) {
		neighbourMasses.add(m);
		
		initialLengthSprings.add(calculateNorm(this, m));
	}

	public void setSpeedToNewSpeed() {
		speed = newSpeed;
	}
	
	public void resetForce() {
		force = new Vector3d(0, 0, 0);
	}
	
	/**
	 * Ajoute une force à la force déjà exercée sur la masse, si elle est non attachée.
	 * @param forceAdded Force à ajouter.
	 */
	public void addForce(Vector3d forceAdded) {
		if (!isAttached) {
			force = Vector3d.add(force, forceAdded);
		}
	}
	
	/**
	 * Prend chaque voisin et calcule la force du ressort qui s'exerce entre eux deux,
	 * et l'additionne à la force globale de la masse.
	 * Si isAttached, ne fait rien.
	 */
	public void addForceFromNeighbours() {
		if (!isAttached) {
			for (int i = 0, size = neighbourMasses.size(); i < size; i++) {
				Vector3d voisinForce = Spring.calculateForce(this, neighbourMasses.get(i), initialLengthSprings.get(i));
				force = Vector3d.add(force, voisinForce);
			}
		}
	}
	
	
	/**
	 * Méthode utilitaire qui calcule la norme entre deux masses.
	 * @param m1 Masse 1.
	 * @param m2 Masse 2.
	 */
	public static float calculateNorm(Mass m1, Mass m2) {
		float deltaX = m1.getPosition().get(0) - m2.getPosition().get(0);
		float deltaY = m1.getPosition().get(1) - m2.getPosition().get(1);
		float deltaZ = m1.getPosition().get(2) - m2.getPosition().get(2);
		return (float)Math.sqrt(deltaX*deltaX + deltaY*deltaY + deltaZ*deltaZ);
	}
	
	
	
}
